/*
 * Copyright (c) 2010-2011, Petr Panteleyev <petr@panteleyev.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.panteleyev.gclient;

import com.google.common.collect.ImmutableList;
import com.google.gdata.data.media.mediarss.MediaThumbnail;
import java.awt.BorderLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collection;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.SwingUtilities;
import javax.swing.text.html.HTML;
import org.panteleyev.blogclient.BloggerEditorFrame;
import org.panteleyev.blogclient.HandleExceptionEDT;
import org.panteleyev.blogclient.Icon;
import org.panteleyev.blogclient.UserProfileManager;
import org.panteleyev.blogclient.photo.ThumbnailPanel;
import org.panteleyev.swing.ClipboardUtil;
import org.panteleyev.swing.MenuProvider;
import org.panteleyev.swing.OSUtil;
import org.panteleyev.swing.SwingFactory;
import org.panteleyev.swing.ToolBarProvider;
import org.panteleyev.swing.filefilters.ImageFileFilter;
import org.panteleyev.utilities.Updatable;

/**
 *
 * @author Petr Panteleyev <petr@panteleyev.org>
 */
final class PicasaAlbumPanel extends ThumbnailPanel<GPicasaGalleryFrame,GPhoto> implements Updatable, MenuProvider, ToolBarProvider {
    private GBUserProfile               profile;
    private GBAccount                   account;
    private GAlbum                      album;

    private AbstractAction              copyPhotoLinkAction;
    private AbstractAction              copyPhotoRawLinkAction;
    private AbstractAction              pictureOpenWebAction = new PictureOpenWebAction();
    private AbstractAction              picturePropertiesAction = new PicturePropertiesAction();
    private AbstractAction              picturePublishAction = new PublichPucturesAction();
    private AbstractAction              uploadPictureAction;

    private ArrayList<AbstractAction>   toolbarActions = new ArrayList<AbstractAction>();

    private final Runnable finishLongOperationEDT = new Runnable() {
        @Override
        public void run() {
            finishLongOperation();
        }
    };

    @Override
    protected int getCellWidth() {
        return 144 + 10;
    }

    private class UploadPhotosThread extends Thread {
        private File[] files;

        UploadPhotosThread(File[] files) {
            this.files = files;
            startLongOperation();
        }

        @Override
        public void run() {
            try {
                for (File file : files) {
                    getAccount().uploadPhoto(getAlbum(), file);
                }
                update();
            } catch (Exception ex) {
                SwingUtilities.invokeLater(new HandleExceptionEDT(getFrame(), ex));
            } finally {
                SwingUtilities.invokeLater(finishLongOperationEDT);
            }
        }
    }

    private class UpdatePhotosThread extends Thread {
        UpdatePhotosThread() {
            startLongOperation();
        }

        @Override
        public void run() {
            try {
                setPictures(account.getPhotos(album));
                updateThumbnails();
            } catch (Exception ex) {
                SwingUtilities.invokeLater(new HandleExceptionEDT(getFrame(), ex));
            } finally {
                SwingUtilities.invokeLater(finishLongOperationEDT);
            }
        }

        private void updateThumbnails() throws IOException, GBException {
            getThumbnails().clear();
            getThumbnails().ensureCapacity(getPictures().size());

            for (GPhoto photo : getPictures()) {
                final URL url = new URL(photo.getThumbnail(1).getUrl());
                ImageIcon thumb = UserProfileManager.loadThumbnail(getProfile(), url);
                if (thumb == null) {
                    final URLConnection conn = url.openConnection();
                    BufferedImage bim = javax.imageio.ImageIO.read(conn.getInputStream());
                    thumb = new ImageIcon(bim);
                    UserProfileManager.storeThumbnail(getProfile(), url, bim);
                }

                getThumbnailsLock().lock();
                try {
                    getThumbnails().add(thumb);
                } finally {
                    getThumbnailsLock().unlock();
                }
                SwingUtilities.invokeLater(getUpdateWindowEDT());
            }
        }
    }

    /** Creates new form GAlbumFrame
     * @param profile
     * @param album
     */
    public PicasaAlbumPanel(GPicasaGalleryFrame frame, GBUserProfile profile, GAlbum album) {
        super(frame);
        this.profile = profile;

        account = profile.getAccount();
        this.album = album;

        createActions();
        initComponents();

        update();
    }

    private GBUserProfile getProfile() {
        return profile;
    }

    private void initComponents() {
        setLayout(new BorderLayout());
        add(getScroller(), BorderLayout.CENTER);
        getScroller().setComponentPopupMenu(createMenu().getPopupMenu());
    }

    GAlbum getAlbum() {
        return album;
    }

    GBAccount getAccount() {
        return account;
    }

    private void createActions() {
        copyPhotoLinkAction = new AbstractAction(L10N.ALBUM_FRAME_COPY_LINK_ACTION.s(), Icon.COPY.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onCopyPhotoLink();
            }
        };
        copyPhotoLinkAction.putValue(Action.LARGE_ICON_KEY, Icon.COPY.I());

        copyPhotoRawLinkAction = new AbstractAction(L10N.ALBUM_WINDOW_COPY_RAW_LINK_ACTION.s(), Icon.COPY.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onCopyPhotoRawLink();
            }
        };
        copyPhotoRawLinkAction.putValue(Action.LARGE_ICON_KEY, Icon.COPY.I());

        uploadPictureAction = new PictureUploadAction();

        toolbarActions.add(uploadPictureAction);
    }

    @Override
    public JMenu createMenu() {
        return SwingFactory.createMenu(PHOTO_MENU_NAME,
                    picturePropertiesAction,
                    null,
                    copyPhotoLinkAction,
                    copyPhotoRawLinkAction,
                    pictureOpenWebAction,
                    null,
                    uploadPictureAction,
                    picturePublishAction);
    }

    public void startLongOperation() {
        getFrame().startLongOperation();
        picturePropertiesAction.setEnabled(false);
        copyPhotoLinkAction.setEnabled(false);
        pictureOpenWebAction.setEnabled(false);
    }

    public void finishLongOperation() {
        picturePropertiesAction.setEnabled(true);
        copyPhotoLinkAction.setEnabled(true);
        pictureOpenWebAction.setEnabled(true);
        getFrame().finishLongOperation();
    }

    @Override
    protected void onPictureProperties(GPhoto picture) {
        new GPhotoPropertiesDialog(getFrame(), picture).showDialog();
    }

    private void onCopyPhotoLink() {
        GPhoto photo = getSelectedPicture();
        if (photo != null) {
            ClipboardUtil.put(photo.getHtmlLinkAsString());
        }
    }

    private void onCopyPhotoRawLink() {
        GPhoto photo = getSelectedPicture();
        if (photo != null) {
            ClipboardUtil.put(photo.getRawImageUrl());
        }
    }

    @Override
    protected void pictureDoubleClicked(GPhoto photo) {
        OSUtil.runBrowser(photo.getHtmlLinkAsString());
    }

    @Override
    protected void onUpload() {
        JFileChooser dial = new JFileChooser();
        dial.setAcceptAllFileFilterUsed(false);
        dial.setDialogTitle("Upload Photos");
        dial.setMultiSelectionEnabled(true);

        dial.addChoosableFileFilter(new ImageFileFilter());

        if (dial.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            final File[] files = dial.getSelectedFiles();
            if (files.length != 0) {
                new UploadPhotosThread(files).start();
            }
        }
    }

    @Override
    protected void onPublishPictures(ImmutableList<GPhoto> pictures) {
        if (!pictures.isEmpty()) {
            GPicturePublishDialog dial = new GPicturePublishDialog(getFrame(), pictures);
            if (dial.showDialog()) {
                StringBuilder b = new StringBuilder();

                b.append("<table");
                if (dial.getBorder()) {
                    b.append(" border='1'");
                }
                b.append(">");

                int nCols = Math.min(dial.getColumnCount(), pictures.size());
                int nRows = pictures.size() / nCols + (int)Math.signum(pictures.size() % nCols);

                int index = 0;

                for (int row = 0; row < nRows; row++) {
                    if (index >= pictures.size()) {
                        break;
                    }

                    b.append("<tr valign='top'>");

                    for (int col = 0; col < nCols; col++) {
                        if (index >= pictures.size()) {
                            break;
                        }

                        GPhoto photo = pictures.get(index++);

                        b.append("<td>");

                        if (dial.getLinkToSource()) {
                            b.append("<a href='");
                            b.append(photo.getRawImageUrl());
                            b.append("'>");
                        }

                        b.append("<img src='");
                        if (dial.getFullSize()) {
                            b.append(photo.getRawImageUrl())
                                .append("'")
                                .append(" width='")
                                .append(photo.getWidth())
                                .append("'")
                                .append(" height='")
                                .append(photo.getHeight())
                                .append("'");
                        } else {
                            int sizeIndex = dial.getSmallSizeIndex();
                            MediaThumbnail thumb = photo.getThumbnail(sizeIndex);
                            String thUrl = thumb.getUrl();
                            b.append(thUrl)
                                .append("'")
                                .append(" width='")
                                .append(thumb.getWidth())
                                .append("'")
                                .append(" height='")
                                .append(thumb.getHeight())
                                .append("'");
                        }
                        b.append(" border='");

                        if (dial.getImageBorder()) {
                            b.append("1'");
                        } else {
                            b.append("0'");
                        }

                        b.append(">");

                        if (dial.getLinkToSource()) {
                            b.append("</a>");
                        }

                        b.append("</td>");
                    }

                    b.append("</tr>");
                }

                b.append("</table>");

                BloggerEditorFrame<?> destWnd = dial.getDestinationWindow();
                if (destWnd == null) {
                    ClipboardUtil.put(b.toString());
                } else {
                    destWnd.getEditor().insertHTML(b.toString(), HTML.Tag.TABLE);
                }
            }
        }
    }

    @Override
    public void update() {
        new UpdatePhotosThread().start();
    }

    @Override
    public Collection<AbstractAction> getToolBarActions() {
        return toolbarActions;
    }
}
